﻿#include "widget.h"
#include "ui_widget.h"
#include <QImage>
#include <QByteArray>
#include <QBuffer>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QScriptEngine>
#include <QScriptValue>
#include <QUrl>
#include <QFileDialog>
#include <QString>
#include <QMessageBox>
#include <QNetworkRequest>
#include <QScriptValueIterator>

const QString APP_ID = "11367835";
const QString API_KEY = "s2WngvgfNb7R35wDelManlCU";
const QString SECRET_KEY = "pFhrIerxgPMSU8oTrwOA7TP4RkKRuO9u";

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget),
    manager(new QNetworkAccessManager(this))
{
    ui->setupUi(this);
    connect(manager, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(replyFinished(QNetworkReply*)));
    clearLabel();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::clearLabel()
{
    ui->label->clear();
    ui->lblAge->clear();
    ui->lblBeauty->clear();
    ui->lblFeature->clear();
    ui->lblSex->clear();
    ui->textEdit->clear();
}

QString Widget::getAccessToken() const
{
    QStringList accessToken;
    accessToken.append(QString("grant_type=%1").arg("client_credentials"));
    accessToken.append(QString("client_id=%1").arg(API_KEY));
    accessToken.append(QString("client_secret=%1").arg(SECRET_KEY));
    QString dataToken = accessToken.join("&");

    QString requestUrl("https://aip.baidubce.com/oauth/2.0/token");
    QString url(requestUrl + "?" + dataToken);
    qDebug() << "Token:"<< url;

    QString access_token;
    auto replyData = getblock(url);

    QJsonParseError json_error;
    QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
    if(json_error.error == QJsonParseError::NoError)
    {
        if(document.isObject())
        {
            QJsonObject obj = document.object();
            if(obj.contains("access_token"))
            {
                access_token = obj.take("access_token").toString();
            }
        }
    }

    qDebug() << access_token;
    return access_token;
}

QByteArray Widget::getblock(const QString &strUrl) const
{
    // https://www.cnblogs.com/roadbike/p/6055263.html
    //    Q_ASSERT(!strUrl.isEmpty());

    const QUrl url = QUrl::fromUserInput(strUrl);
    //    Q_ASSERT(url.isValid());

    QNetworkRequest qnr(url);
    QNetworkAccessManager man;
    QNetworkReply* reply = man.get(qnr);

    QEventLoop eventLoop;
    connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);

    QByteArray replyData = reply->readAll();
    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    QVariant redirectAttr = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
    if (reply->error()
            || 300 == statusCode //状态码300 Multiple Choices，既不是错误也不算重定向，应该是qt bug
            || !redirectAttr.isNull())
    {
        QString errString = reply->error() ? reply->errorString() : QString("发生重定向(%1)，不允许此情况").arg(statusCode);
        QMessageBox::critical(nullptr, "网络异常",
                              QString("发送get请求时出现错误：\n网址：%1\n错误信息：%2").arg(reply->request().url().toDisplayString(), errString));
        replyData.clear();
    }

    reply->deleteLater();
    reply = nullptr;

    return replyData;
}

QString Widget::getImageData(const QString &img) const
{
    QImage image(img);
    QByteArray imageData;
    QBuffer buffer(&imageData);
    image.save(&buffer, "jpg");
    QString data = QString(imageData.toBase64());
    return data;
}

void Widget::on_start_clicked()
{
    if (imageFile.isEmpty() || imageFile.isNull())
    {
        qDebug() << "data is Empty";
        return;
    }

    QString imgData(getImageData(imageFile));
    if (imgData.isNull() || imgData.isEmpty())
    {
        qDebug() << "data is Empty";
        return;
    }

    clearLabel();
    QImage img(imageFile);
    QImage scaledimg = img.scaled(ui->label->width(),ui->label->height(),Qt::KeepAspectRatio);
    ui->label->setScaledContents(true);
    ui->label->setPixmap(QPixmap::fromImage(scaledimg));

    // baidu API
    // https://ai.baidu.com/ai-doc/FACE/yk37c1u4t
    QString dataToken = getAccessToken();
    QString requestUrl("https://aip.baidubce.com/rest/2.0/face/v3/detect");
    QUrl url(requestUrl + "?access_token=" + dataToken);
    qDebug() << url;
    QNetworkRequest request(url);

    //设置数据提交格式，这个不能自己随便写，每个平台的格式可能不一样，百度AI要求的格式为application/json
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //打包请求参数
    QJsonObject post_data;;
    QJsonDocument document;

    post_data.insert("image", imgData);
    post_data.insert("image_type", "BASE64");
    post_data.insert("face_field", "age,beauty,gender,expression");
    document.setObject(post_data);
    QByteArray post_param = document.toJson(QJsonDocument::Compact);

    //发送请求
    this->manager->post(request, post_param);
}

void Widget::on_open_clicked()
{
    imageFile = QFileDialog::getOpenFileName(this, tr("Open File"),
                                             "",
                                             tr("Images (*.png *.jpg)"));
    on_start_clicked();
}

void Widget::replyFinished(QNetworkReply* reply)
{
    // https://blog.csdn.net/zbw1185/article/details/81814769
    auto replyData = reply->readAll();
    qDebug()<< "reply data is:" << QString(replyData);
    ui->textEdit->setText(QString(replyData));

    QJsonParseError json_error;
    QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
    if(json_error.error == QJsonParseError::NoError)
    {
        //判断是否是对象,然后开始解析数据
        if(document.isObject())
        {
            QJsonObject obj = document.object();
            //解析反馈的人脸属性结果
            if(obj.contains("result"))
            {
                QJsonObject resultObj = obj.take("result").toObject();
                //解析人脸个数
                if(resultObj.contains("face_num"))
                {
                    int faceNum = obj.take("face_num").toInt();
                    qDebug()<<"查询到了图片中的人脸个数为："<<faceNum;
                }
                //解析人脸属性
                if(resultObj.contains("face_list"))
                {
                    QJsonArray faceArray = resultObj.take("face_list").toArray();

                    for(int i = 0; i < faceArray.size(); i++)
                    {
                        QJsonObject faceObj = faceArray.at(i).toObject();
                        if(faceObj.contains("gender"))
                        {
                            QJsonObject genderObj = faceObj.take("gender").toObject();
                            if(genderObj.contains("type"))
                            {
                                QString type = genderObj.take("type").toString();;
                                if(type == "male")
                                {
                                    ui->lblSex->setText("性别：男");
                                }
                                else
                                {
                                    ui->lblSex->setText("性别：女");
                                }
                            }
                        }

                        if(faceObj.contains("age"))
                        {
                            int age = faceObj.take("age").toDouble();
                            qDebug()<<"查询到了年龄："<<age;
                            ui->lblAge->setText(QString("年龄：") + QString::number(age));
                        }

                        if(faceObj.contains("beauty"))
                        {
                            int beauty = faceObj.take("beauty").toDouble();;
                            qDebug()<<"查询到了颜值："<<beauty;
                            ui->lblBeauty->setText(QString("颜值：") + QString::number(beauty));
                        }

                        if(faceObj.contains("expression"))
                        {
                            QJsonObject expressionObj = faceObj.take("expression").toObject();
                            if(expressionObj.contains("type"))
                            {
                                QString type = expressionObj.take("type").toString();;
                                if(type == "smile")
                                {
                                    ui->lblFeature->setText("笑容：微笑");
                                }
                                else if(type == "laugh")
                                {
                                    ui->lblFeature->setText("笑容：大笑");
                                }
                                else
                                {
                                    ui->lblFeature->setText("笑容：不笑");
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    reply->deleteLater();
}
